import java.io.File


// 人
 open class Person

// 老师
 open class Teacher : Person()

// 博士
 open class Doctor : Teacher()


// 测试类型的上下界
fun testBound() {
    // out 表示 存入的值只能是Teacher或者Teacher的子类，但是不知道其具体类型
    // out 同时也表示producer 即被范性约束的类的与类范型相同的方法的返回值的类型必须为Teacher
    val outTeachers: MutableList<out Teacher> = arrayListOf(Teacher())

    //所以不能加人任何元素
//    teachers.add(Person()) // compile error
//    teachers.add(Teacher()) // compile error
//    teachers.add(Student()) // compile error
    // 但是取出的元素必然为Teach类型或者其子类
    val teacher = outTeachers[0] // compile success
    // 必然为true
    assert(teacher is Teacher)
    // in 表示存入的元素是Teacher或者Teacher的父类
    // 同时也是消费者，即被范性约束的类的与类范型相同的方法入参的类型必须为Teacher
    val inTeachers: MutableList<in Teacher> = ArrayList()
    inTeachers.add(Doctor())
    inTeachers.add(Teacher())

    // 不知道具体的类型，所有范型约束的方法的返回值都变为Any
    val get: Any? = inTeachers.get(0)

    val personList = listOf<Person>()
    val teacherList = listOf<Teacher>()
    println(teacherList)

}

interface GenericBase<T:Person>{
    fun set(collection: List<T>)
    fun get(): Collection<T>
}
interface GenericSub<T:Teacher>: GenericBase<T>{
    override fun get(): List<T>
}
interface GenericSub2<T:Doctor>: GenericBase<T>{
    override fun get(): ArrayList<T>
}
interface A<T:Person>
interface B:A<Teacher>

// 泛型的使用
fun test1() {
    val list: MutableList<*> = ArrayList<Any?>()
}

fun <T> test2() where  T : List<String>, T : Comparable<String> {}

// 泛型的约束
//1 无法在静态字段上使用类型参数
class MobileDevice<T> {
    companion object {
//        类的静态字段是一个类级别变量，由类的所有非静态对象共享。因此，类型参数的静态字段是不允许的
//        private val os: T? = null
    }
}

//2 无法创建、捕获或抛出参数化类型的对象
fun <E : Throwable> testError() {
//    try {
//
//        // Type parameter is forbidden for catch parameter
//    }catch (e:E){
//        e.printStackTrace()
//    }
}
// Extends Throwable indirectly
//class MathException<T> : Exception() { /* ... */ }    // compile-time error

// Extends Throwable directly
//class QueueFullException<T> : Throwable() { /* ... */ // compile-time error

// 无法抛出泛型异常
internal class Parser<out T : Exception> {
    //    @Throws(T::class) compile-time error
    fun parse(file: File?) {     // OK
        // ...
    }
}

// java中可以
//```
// class Parser<T extends Exception> {
//    public void parse(File file) throws T {     // OK
//        // ...
//    }
//}
//```
//
// 3 无法重载两个泛型擦出后具有相同签名的方法
class Example {
    // 虽然编译器会擦出泛型信息，但是只要具体的type为ParameterizedType,运行时仍然可以获取到泛型信息
    // Example::class.java.methods[0].parameters[0].parameterizedType
    // rawType Set  typeArguments String
    fun print(strSet: Set<String>) {}
    // 编译错误
//    fun print(intSet: Set<Int>) {}
}

// 4 is无法作用与泛型类型
// 因为 Java 编译器会擦除泛型代码中的所有类型参数，所以无法验证在运行时使用的泛型类型的参数化类型:
fun <E> rtti(list: List<E>?) {
    if (list is ArrayList<*>) {  // OK; instanceof requires a reifiable type
        // ...
    }

//    if (list is ArrayList<Int?>) {  // compile-time error
//    }
}

//5 无法创建类型参数的实例  C# 和typescript可以
fun <T> create(list: List<T>) {
//    val a =T()

}

//6 无法在注解中使用泛型
//annotation class Test<St> (val value: St)

